# -*- coding: utf-8 -*-
"""
@Time    : 2024/7/9 13:32 
@Author  : ZhangShenao 
@File    : shallow_copy.py 
@Desc    : 浅拷贝
所谓shallow copy浅拷贝,是指重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用
新对象与原对象,通过==判断返回True,通过is判断返回False

浅拷贝会产生一些副作用,因为拷贝对象与原对象会共享一部分子对象
"""
import copy


def create_shallow_copy():
    """
    浅拷贝的创建方式
    """

    # 通过数据类型自身的构造器,实现shallow copy浅拷贝
    l1 = [1, 2, 3]
    # l2是l1的浅拷贝
    l2 = list(l1)
    print(f'l1 == l2: {l1 == l2}')  # l1 == l2: True l1和l2的值相等
    print(f'l1 is l2: {l1 is l2}')  # l1 is l2: False l1和l2指向不同的对象

    s1 = {1, 2, 3}
    s2 = set(s1)
    print(f's1 == s2: {s1 == s2}')  # s1 == s2: True s1和s2的值相等
    print(f's1 is s2: {s1 is s2}')  # s1 is s2: False s1和s2指向不同的对象

    # 通过对可变序列的切片操作,如list[:],实现浅拷贝
    l3 = l1[:]
    print(f'l1 == l3: {l1 == l3}')  # l1 == l3: True l1和l3的值相等
    print(f'l1 is l3: {l1 is l3}')  # l1 is l3: False l1和l3指向不同的对象

    # 通过内置的copy.copy函数,可以实现浅拷贝
    # 这种方式适用于任何数据类型
    l4 = copy.copy(l1)
    print(f'l1 == l4: {l1 == l4}')  # l1 == l4: True l1和l4的值相等
    print(f'l1 is l4: {l1 is l4}')  # l1 is l4: False l1和l4指向不同的对象

    # 对于tuple来说,情况比较特殊,因为它是Immutable的
    # 因此使用tuple()构造函数,或者通过切片操作,返回的新tuple,都是和原tuple指向同一个对象
    t1 = (1, 2, 3)
    t2 = tuple(t1)
    print(f't1 == t2: {t1 == t2}')  # t1 == t2: True t1和t2的值相等
    print(f't1 is t2: {t1 is t2}')  # t1 is t2: True t1和t2指向同一个对象
    t3 = t1[:]
    print(f't1 == t3: {t1 == t3}')  # t1 == t3: True t1和t3的值相等
    print(f't1 is t3: {t1 is t3}')  # t1 is t3: True t1和t3指向同一个对象


def side_effect():
    """
    浅拷贝会产生一些副作用,因为拷贝对象与原对象会共享一部分子对象
    """

    # 创建原始对象
    l1 = [[1, 2], (30, 40)]

    # 创建浅拷贝对象
    # l2与l1整体是两个不同的对象,但是内部的元素指向同一个内存地址,是共享的
    l2 = list(l1)

    # 修改l1整体,并不会影响l2
    l1.append(100)
    print(f'l1: {l1}')  # l1: [[1, 2], (30, 40), 100]
    print(f'l2: {l2}')  # l2: [[1, 2], (30, 40)]

    # 修改l1内部的可变元素,因为l2与l1共享内部元素,因此会影响l2
    l1[0].append(3)
    print(f'l1: {l1}')  # l1: [[1, 2, 3], (30, 40), 100]
    print(f'l2: {l2}')  # l2: [[1, 2, 3], (30, 40)]

    # 修改l1内部的Immutable元素,会创建新的对象,而l2中的内部元素还是原对象,因此l2不会受到影响
    l1[1] += (50, 50)
    print(f'l1: {l1}')  # l1: [[1, 2, 3], (30, 40, 50, 50), 100]
    print(f'l2: {l2}')  # l2: [[1, 2, 3], (30, 40)]


if __name__ == '__main__':
    side_effect()
